//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_idea_api_serv

import (
	"context"
	"strings"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/idea_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/project_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_idea"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_idea_api"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_recycle_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectIdeaApiImpl) adjustKeyword(keywordList []string) []string {
	retList := []string{}
	tmpMap := map[string]bool{}
	for _, keyword := range keywordList {
		keyword = strings.ToLower(keyword)
		if tmpMap[keyword] {
			continue
		}
		retList = append(retList, keyword)
		tmpMap[keyword] = true
	}
	return retList
}

func (apiImpl *ProjectIdeaApiImpl) CreateIdea(ctx context.Context, req *project_idea_api.CreateIdeaRequest) (*project_idea_api.CreateIdeaResponse, error) {
	req.BasicInfo.KeywordList = apiImpl.adjustKeyword(req.BasicInfo.KeywordList)
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.CreateIdeaResponse{
			Code:   project_idea_api.CreateIdeaResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.CreateIdeaResponse{
			Code:   project_idea_api.CreateIdeaResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.CreateIdeaResponse{
			Code:   project_idea_api.CreateIdeaResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_idea_api.CreateIdeaResponse{
			Code:   project_idea_api.CreateIdeaResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//检查分组是否存在
	if req.IdeaGroupId == "" {
		req.IdeaGroupId = projectItem.DefaultIdeaGroupId
	}
	exist, err := idea_dao.IdeaGroupDao.Exist(ctx, req.ProjectId, req.IdeaGroupId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_idea_api.CreateIdeaResponse{
			Code:   project_idea_api.CreateIdeaResponse_CODE_NO_IDEA_GROUP,
			ErrMsg: "知识点分组不存在",
		}, nil
	}
	//检查权限用户
	if req.IdeaPerm == nil {
		req.IdeaPerm = &project_idea_api.IdeaPerm{
			UpdateForAll:          true,
			ExtraUpdateUserIdList: []string{},
		}
	}
	if len(req.IdeaPerm.ExtraUpdateUserIdList) > 0 {
		memberUserIdList, err := project_dao.MemberInfoDao.ListMemberId(ctx, req.ProjectId)
		if err != nil {
			return nil, err
		}
		memberUserIdMap := map[string]bool{}
		for _, memberUserId := range memberUserIdList {
			memberUserIdMap[memberUserId] = true
		}
		for _, userId := range req.IdeaPerm.ExtraUpdateUserIdList {
			_, ok := memberUserIdMap[userId]
			if !ok {
				return &project_idea_api.CreateIdeaResponse{
					Code:   project_idea_api.CreateIdeaResponse_CODE_NO_MEMBER,
					ErrMsg: "项目成员不存在",
				}, nil
			}
		}
	}

	ideaId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = idea_dao.IdeaDao.Insert(sessCtx, &idea_dao.IdeaDbItem{
			IdeaId:    ideaId,
			ProjectId: req.ProjectId,
			BasicInfo: idea_dao.BasicIdeaDbItem{
				Title:       req.BasicInfo.Title,
				Content:     req.BasicInfo.Content,
				KeywordList: req.BasicInfo.KeywordList,
			},
			AgreeValue:    0,
			AgreeCount:    0,
			DisagreeCount: 0,
			CreateUserId:  sessionItem.UserId,
			UpdateUserId:  sessionItem.UserId,
			CreateTime:    nowTime,
			UpdateTime:    nowTime,
			IdeaGroupId:   req.IdeaGroupId,
			IdeaPerm: idea_dao.IdeaPermDbItem{
				UpdateForAll:          req.IdeaPerm.UpdateForAll,
				ExtraUpdateUserIdList: req.IdeaPerm.ExtraUpdateUserIdList,
			},
		})
		if err != nil {
			return nil, err
		}
		//更新知识点分组
		count, err := idea_dao.IdeaDao.Count(sessCtx, req.ProjectId, &project_idea_api.ListIdeaParam{
			FilterByGroupId: true,
			GroupId:         req.IdeaGroupId,
		})
		if err != nil {
			return nil, err
		}
		err = idea_dao.IdeaGroupDao.UpdateIdeaCount(sessCtx, req.ProjectId, req.IdeaGroupId, count)
		if err != nil {
			return nil, err
		}
		return &project_idea_api.CreateIdeaResponse{
			Code:   project_idea_api.CreateIdeaResponse_CODE_OK,
			IdeaId: ideaId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addCreateIdeaEvent(sessionItem, req, projectItem, ideaId, nowTime)
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.CreateIdeaNotice{
		ProjectId:   req.ProjectId,
		IdeaGroupId: req.IdeaGroupId,
	})
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.UpdateGroupNotice{
		ProjectId:   req.ProjectId,
		IdeaGroupId: req.IdeaGroupId,
	})
	return ret.(*project_idea_api.CreateIdeaResponse), nil
}

func (apiImpl *ProjectIdeaApiImpl) UpdateIdeaContent(ctx context.Context, req *project_idea_api.UpdateIdeaContentRequest) (*project_idea_api.UpdateIdeaContentResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.UpdateIdeaContentResponse{
			Code:   project_idea_api.UpdateIdeaContentResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.UpdateIdeaContentResponse{
			Code:   project_idea_api.UpdateIdeaContentResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.UpdateIdeaContentResponse{
			Code:   project_idea_api.UpdateIdeaContentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_idea_api.UpdateIdeaContentResponse{
			Code:   project_idea_api.UpdateIdeaContentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查idea是否存在
	ideaItem, err := idea_dao.IdeaDao.Get(ctx, req.ProjectId, req.IdeaId)
	if err != nil {
		return &project_idea_api.UpdateIdeaContentResponse{
			Code:   project_idea_api.UpdateIdeaContentResponse_CODE_NO_IDEA,
			ErrMsg: "知识点不存在",
		}, nil
	}

	//检查权限
	userPerm := apiImpl.calcUserPerm(projectItem, roleItem, sessionItem.UserId, ideaItem)
	if !userPerm.CanUpdate {
		return &project_idea_api.UpdateIdeaContentResponse{
			Code:   project_idea_api.UpdateIdeaContentResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = idea_dao.IdeaDao.UpdateContent(sessCtx, req.ProjectId, req.IdeaId, req.Title, req.Content, sessionItem.UserId, nowTime)
		if err != nil {
			return nil, err
		}
		return &project_idea_api.UpdateIdeaContentResponse{
			Code: project_idea_api.UpdateIdeaContentResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addUpateIdeaContentEvent(sessionItem, req, projectItem, ideaItem, nowTime)
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.UpdateIdeaNotice{
		ProjectId: req.ProjectId,
		IdeaId:    req.IdeaId,
	})
	return ret.(*project_idea_api.UpdateIdeaContentResponse), nil
}

func (apiImpl *ProjectIdeaApiImpl) UpdateIdeaKeyword(ctx context.Context, req *project_idea_api.UpdateIdeaKeywordRequest) (*project_idea_api.UpdateIdeaKeywordResponse, error) {
	req.KeywordList = apiImpl.adjustKeyword(req.KeywordList)

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.UpdateIdeaKeywordResponse{
			Code:   project_idea_api.UpdateIdeaKeywordResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.UpdateIdeaKeywordResponse{
			Code:   project_idea_api.UpdateIdeaKeywordResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.UpdateIdeaKeywordResponse{
			Code:   project_idea_api.UpdateIdeaKeywordResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_idea_api.UpdateIdeaKeywordResponse{
			Code:   project_idea_api.UpdateIdeaKeywordResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查idea是否存在
	ideaItem, err := idea_dao.IdeaDao.Get(ctx, req.ProjectId, req.IdeaId)
	if err != nil {
		return &project_idea_api.UpdateIdeaKeywordResponse{
			Code:   project_idea_api.UpdateIdeaKeywordResponse_CODE_NO_IDEA,
			ErrMsg: "知识点不存在",
		}, nil
	}
	//检查权限
	userPerm := apiImpl.calcUserPerm(projectItem, roleItem, sessionItem.UserId, ideaItem)
	if !userPerm.CanUpdate {
		return &project_idea_api.UpdateIdeaKeywordResponse{
			Code:   project_idea_api.UpdateIdeaKeywordResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = idea_dao.IdeaDao.UpdateKeywordList(sessCtx, req.ProjectId, req.IdeaId, req.KeywordList, sessionItem.UserId, nowTime)
		if err != nil {
			return nil, err
		}
		return &project_idea_api.UpdateIdeaKeywordResponse{
			Code: project_idea_api.UpdateIdeaKeywordResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addUpdateIdeaKeywordEvent(sessionItem, req, projectItem, ideaItem, nowTime)
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.UpdateIdeaNotice{
		ProjectId: req.ProjectId,
		IdeaId:    req.IdeaId,
	})
	return ret.(*project_idea_api.UpdateIdeaKeywordResponse), nil
}

func (apiImpl *ProjectIdeaApiImpl) UpdateIdeaPerm(ctx context.Context, req *project_idea_api.UpdateIdeaPermRequest) (*project_idea_api.UpdateIdeaPermResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.UpdateIdeaPermResponse{
			Code:   project_idea_api.UpdateIdeaPermResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.UpdateIdeaPermResponse{
			Code:   project_idea_api.UpdateIdeaPermResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.UpdateIdeaPermResponse{
			Code:   project_idea_api.UpdateIdeaPermResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_idea_api.UpdateIdeaPermResponse{
			Code:   project_idea_api.UpdateIdeaPermResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查权限用户
	if req.IdeaPerm == nil {
		req.IdeaPerm = &project_idea_api.IdeaPerm{
			ExtraUpdateUserIdList: []string{},
		}
	}
	if len(req.IdeaPerm.ExtraUpdateUserIdList) > 0 {
		memberUserIdList, err := project_dao.MemberInfoDao.ListMemberId(ctx, req.ProjectId)
		if err != nil {
			return nil, err
		}
		memberUserIdMap := map[string]bool{}
		for _, memberUserId := range memberUserIdList {
			memberUserIdMap[memberUserId] = true
		}
		for _, userId := range req.IdeaPerm.ExtraUpdateUserIdList {
			_, ok := memberUserIdMap[userId]
			if !ok {
				return &project_idea_api.UpdateIdeaPermResponse{
					Code:   project_idea_api.UpdateIdeaPermResponse_CODE_NO_MEMBER,
					ErrMsg: "项目成员不存在",
				}, nil
			}
		}
	}

	//检查idea是否存在
	ideaItem, err := idea_dao.IdeaDao.Get(ctx, req.ProjectId, req.IdeaId)
	if err != nil {
		return &project_idea_api.UpdateIdeaPermResponse{
			Code:   project_idea_api.UpdateIdeaPermResponse_CODE_NO_IDEA,
			ErrMsg: "知识点不存在",
		}, nil
	}
	//检查权限
	userPerm := apiImpl.calcUserPerm(projectItem, roleItem, sessionItem.UserId, ideaItem)
	if !userPerm.CanUpdate {
		return &project_idea_api.UpdateIdeaPermResponse{
			Code:   project_idea_api.UpdateIdeaPermResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = idea_dao.IdeaDao.UpdateIdeaPerm(sessCtx, req.ProjectId, req.IdeaId, &idea_dao.IdeaPermDbItem{
			UpdateForAll:          req.IdeaPerm.UpdateForAll,
			ExtraUpdateUserIdList: req.IdeaPerm.ExtraUpdateUserIdList,
		}, sessionItem.UserId, nowTime)
		if err != nil {
			return nil, err
		}
		return &project_idea_api.UpdateIdeaPermResponse{
			Code: project_idea_api.UpdateIdeaPermResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.UpdateIdeaNotice{
		ProjectId: req.ProjectId,
		IdeaId:    req.IdeaId,
	})
	return ret.(*project_idea_api.UpdateIdeaPermResponse), nil
}

func (apiImpl *ProjectIdeaApiImpl) MoveIdea(ctx context.Context, req *project_idea_api.MoveIdeaRequest) (*project_idea_api.MoveIdeaResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.MoveIdeaResponse{
			Code:   project_idea_api.MoveIdeaResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.MoveIdeaResponse{
			Code:   project_idea_api.MoveIdeaResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.MoveIdeaResponse{
			Code:   project_idea_api.MoveIdeaResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_idea_api.MoveIdeaResponse{
			Code:   project_idea_api.MoveIdeaResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	//检查目标分组是否存在
	exist, err := idea_dao.IdeaGroupDao.Exist(ctx, req.ProjectId, req.IdeaGroupId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_idea_api.MoveIdeaResponse{
			Code:   project_idea_api.MoveIdeaResponse_CODE_NO_IDEA_GROUP,
			ErrMsg: "知识点分组不存在",
		}, nil
	}
	//检查idea是否存在
	ideaItem, err := idea_dao.IdeaDao.Get(ctx, req.ProjectId, req.IdeaId)
	if err != nil {
		return &project_idea_api.MoveIdeaResponse{
			Code:   project_idea_api.MoveIdeaResponse_CODE_NO_IDEA,
			ErrMsg: "知识点不存在",
		}, nil
	}
	//检查权限
	userPerm := apiImpl.calcUserPerm(projectItem, roleItem, sessionItem.UserId, ideaItem)
	if !userPerm.CanUpdate {
		return &project_idea_api.MoveIdeaResponse{
			Code:   project_idea_api.MoveIdeaResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if ideaItem.IdeaGroupId == req.IdeaGroupId {
		return &project_idea_api.MoveIdeaResponse{
			Code: project_idea_api.MoveIdeaResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = idea_dao.IdeaDao.UpdateIdeaGroupId(sessCtx, req.ProjectId, req.IdeaId, req.IdeaGroupId)
		if err != nil {
			return nil, err
		}
		//调整原分组数量
		{
			count, err := idea_dao.IdeaDao.Count(sessCtx, req.ProjectId, &project_idea_api.ListIdeaParam{
				FilterByGroupId: true,
				GroupId:         ideaItem.IdeaGroupId,
			})
			if err != nil {
				return nil, err
			}
			err = idea_dao.IdeaGroupDao.UpdateIdeaCount(sessCtx, req.ProjectId, ideaItem.IdeaGroupId, count)
			if err != nil {
				return nil, err
			}
		}
		//调整新分组数量
		{
			count, err := idea_dao.IdeaDao.Count(sessCtx, req.ProjectId, &project_idea_api.ListIdeaParam{
				FilterByGroupId: true,
				GroupId:         req.IdeaGroupId,
			})
			if err != nil {
				return nil, err
			}
			err = idea_dao.IdeaGroupDao.UpdateIdeaCount(sessCtx, req.ProjectId, req.IdeaGroupId, count)
			if err != nil {
				return nil, err
			}
		}
		return &project_idea_api.MoveIdeaResponse{
			Code: project_idea_api.MoveIdeaResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.MoveIdeaNotice{
		ProjectId:       req.ProjectId,
		IdeaId:          req.IdeaId,
		FromIdeaGroupId: ideaItem.IdeaGroupId,
		ToIdeaGroupId:   req.IdeaGroupId,
	})
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.UpdateGroupNotice{
		ProjectId:   req.ProjectId,
		IdeaGroupId: req.IdeaGroupId,
	})
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.UpdateGroupNotice{
		ProjectId:   req.ProjectId,
		IdeaGroupId: ideaItem.IdeaGroupId,
	})
	return ret.(*project_idea_api.MoveIdeaResponse), nil
}

func (apiImpl *ProjectIdeaApiImpl) GetIdea(ctx context.Context, req *project_idea_api.GetIdeaRequest) (*project_idea_api.GetIdeaResponse, error) {
	emptyIdea := &project_idea_api.Idea{
		BasicInfo: &project_idea_api.BasicIdea{
			KeywordList: []string{},
		},
		UserPerm: &project_idea_api.UserPerm{},
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.GetIdeaResponse{
			Code:   project_idea_api.GetIdeaResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
			Idea:   emptyIdea,
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.GetIdeaResponse{
			Code:   project_idea_api.GetIdeaResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
			Idea:   emptyIdea,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.GetIdeaResponse{
			Code:   project_idea_api.GetIdeaResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
			Idea:   emptyIdea,
		}, nil
	} else if err != nil {
		return nil, err
	}

	ideaItem, err := idea_dao.IdeaDao.Get(ctx, req.ProjectId, req.IdeaId)
	if err != nil {
		return &project_idea_api.GetIdeaResponse{
			Code:   project_idea_api.GetIdeaResponse_CODE_NO_IDEA,
			ErrMsg: "知识点不存在",
			Idea:   emptyIdea,
		}, nil
	}
	//补充用户信息
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, []string{ideaItem.CreateUserId, ideaItem.UpdateUserId})
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	//获取我的点赞信息
	hasMyAppraise := false
	myAppraiseType := project_idea_api.APPRAISE_TYPE_APPRAISE_AGREE
	appraiseItem, err := idea_dao.AppraiseDao.Get(ctx, req.IdeaId, sessionItem.UserId)
	if err == nil {
		hasMyAppraise = true
		myAppraiseType = project_idea_api.APPRAISE_TYPE(appraiseItem.AppraiseType)
	}
	//生成结果
	ideaInfo := ideaItem.ToIdea()
	ideaInfo.HasMyAppraise = hasMyAppraise
	ideaInfo.MyAppraiseType = myAppraiseType
	ideaInfo.UserPerm = apiImpl.calcUserPerm(projectItem, roleItem, sessionItem.UserId, ideaItem)
	createUser, ok := userItemMap[ideaItem.CreateUserId]
	if ok {
		ideaInfo.CreateDisplayName = createUser.BasicInfo.DisplayName
		ideaInfo.CreateLogoUri = createUser.BasicInfo.LogoUri
	}
	updateUser, ok := userItemMap[ideaItem.UpdateUserId]
	if ok {
		ideaInfo.UpdateDisplayName = updateUser.BasicInfo.DisplayName
		ideaInfo.UpdateLogoUri = updateUser.BasicInfo.LogoUri
	}
	return &project_idea_api.GetIdeaResponse{
		Code: project_idea_api.GetIdeaResponse_CODE_OK,
		Idea: ideaInfo,
	}, nil
}

func (apiImpl *ProjectIdeaApiImpl) calcUserPerm(projectItem *project_dao.ProjectInfoDbItem, roleItem *project_dao.RoleInfoDbItem, memberUserId string, ideaItem *idea_dao.IdeaDbItem) *project_idea_api.UserPerm {
	retPerm := &project_idea_api.UserPerm{}
	if projectItem.Closed {
		return retPerm
	}
	if projectItem.OwnerUserId == memberUserId || roleItem.BasicInfo.Admin {
		retPerm.CanRemove = true
		retPerm.CanMove = true
		retPerm.CanUpdate = true
	}
	if ideaItem.CreateUserId == memberUserId {
		retPerm.CanRemove = true
	}
	if ideaItem.IdeaPerm.UpdateForAll {
		retPerm.CanUpdate = true
	}
	for _, userId := range ideaItem.IdeaPerm.ExtraUpdateUserIdList {
		if userId == memberUserId {
			retPerm.CanUpdate = true
		}
	}

	retPerm.CanAppraise = true
	return retPerm
}

func (apiImpl *ProjectIdeaApiImpl) ListIdea(ctx context.Context, req *project_idea_api.ListIdeaRequest) (*project_idea_api.ListIdeaResponse, error) {
	emptyList := []*project_idea_api.Idea{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.ListIdeaResponse{
			Code:     project_idea_api.ListIdeaResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			IdeaList: emptyList,
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.ListIdeaResponse{
			Code:     project_idea_api.ListIdeaResponse_CODE_NO_PROJECT,
			ErrMsg:   "项目不存在",
			IdeaList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.ListIdeaResponse{
			Code:     project_idea_api.ListIdeaResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			IdeaList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	count, err := idea_dao.IdeaDao.Count(ctx, req.ProjectId, req.ListParam)
	if err != nil {
		return nil, err
	}
	ideaItemList, err := idea_dao.IdeaDao.List(ctx, req.ProjectId, req.ListParam, req.SortType, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}
	//补充用户信息
	userIdList := []string{}
	for _, ideaItem := range ideaItemList {
		userIdList = append(userIdList, ideaItem.CreateUserId)
		userIdList = append(userIdList, ideaItem.UpdateUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	//获取我的点赞信息
	ideaIdList := []string{}
	for _, ideaItem := range ideaItemList {
		ideaIdList = append(ideaIdList, ideaItem.IdeaId)
	}
	appraiseItemList, err := idea_dao.AppraiseDao.ListByMember(ctx, ideaIdList, sessionItem.UserId)
	if err != nil {
		return nil, err
	}
	appraiseMap := map[string]project_idea_api.APPRAISE_TYPE{}
	for _, appraiseItem := range appraiseItemList {
		appraiseMap[appraiseItem.IdeaId] = project_idea_api.APPRAISE_TYPE(appraiseItem.AppraiseType)
	}
	//生成结果
	ideaInfoList := []*project_idea_api.Idea{}
	for _, ideaItem := range ideaItemList {
		ideaInfo := ideaItem.ToIdea()
		myAppraiseType, ok := appraiseMap[ideaItem.IdeaId]
		ideaInfo.HasMyAppraise = ok
		ideaInfo.MyAppraiseType = myAppraiseType
		ideaInfo.UserPerm = apiImpl.calcUserPerm(projectItem, roleItem, sessionItem.UserId, ideaItem)
		createUser, ok := userItemMap[ideaItem.CreateUserId]
		if ok {
			ideaInfo.CreateDisplayName = createUser.BasicInfo.DisplayName
			ideaInfo.CreateLogoUri = createUser.BasicInfo.LogoUri
		}
		updateUser, ok := userItemMap[ideaItem.UpdateUserId]
		if ok {
			ideaInfo.UpdateDisplayName = updateUser.BasicInfo.DisplayName
			ideaInfo.UpdateLogoUri = updateUser.BasicInfo.LogoUri
		}
		ideaInfoList = append(ideaInfoList, ideaInfo)
	}
	return &project_idea_api.ListIdeaResponse{
		Code:       project_idea_api.ListIdeaResponse_CODE_OK,
		TotalCount: count,
		IdeaList:   ideaInfoList,
	}, nil
}

func (apiImpl *ProjectIdeaApiImpl) RemoveIdea(ctx context.Context, req *project_idea_api.RemoveIdeaRequest) (*project_idea_api.RemoveIdeaResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.RemoveIdeaResponse{
			Code:   project_idea_api.RemoveIdeaResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.RemoveIdeaResponse{
			Code:   project_idea_api.RemoveIdeaResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.RemoveIdeaResponse{
			Code:   project_idea_api.RemoveIdeaResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_idea_api.RemoveIdeaResponse{
			Code:   project_idea_api.RemoveIdeaResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	//检查idea是否存在
	ideaItem, err := idea_dao.IdeaDao.Get(ctx, req.ProjectId, req.IdeaId)
	if err != nil {
		return &project_idea_api.RemoveIdeaResponse{
			Code:   project_idea_api.RemoveIdeaResponse_CODE_NO_IDEA,
			ErrMsg: "知识点不存在",
		}, nil
	}

	userPerm := apiImpl.calcUserPerm(projectItem, roleItem, sessionItem.UserId, ideaItem)
	if !userPerm.CanRemove {
		return &project_idea_api.RemoveIdeaResponse{
			Code:   project_idea_api.RemoveIdeaResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = idea_dao.IdeaDao.Remove(sessCtx, req.ProjectId, req.IdeaId)
		if err != nil {
			return nil, err
		}
		err = idea_dao.IdeaRecycleDao.Insert(sessCtx, ideaItem)
		if err != nil {
			return nil, err
		}
		err = project_dao.RecycleDao.Insert(sessCtx, &project_dao.RecycleItemInfoDbItem{
			RecycleItemId:   req.IdeaId,
			ProjectId:       req.ProjectId,
			RecycleItemType: uint32(project_recycle_api.RECYCLE_ITEM_TYPE_RECYCLE_ITEM_IDEA),
			RemoveUserId:    sessionItem.UserId,
			RemoveTime:      nowTime,
		})
		if err != nil {
			return nil, err
		}
		//调整分组计数
		count, err := idea_dao.IdeaDao.Count(sessCtx, req.ProjectId, &project_idea_api.ListIdeaParam{
			FilterByGroupId: true,
			GroupId:         ideaItem.IdeaGroupId,
		})
		if err != nil {
			return nil, err
		}
		err = idea_dao.IdeaGroupDao.UpdateIdeaCount(sessCtx, req.ProjectId, ideaItem.IdeaGroupId, count)
		if err != nil {
			return nil, err
		}
		return &project_idea_api.RemoveIdeaResponse{
			Code: project_idea_api.RemoveIdeaResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addRemoveIdeaEvent(sessionItem, projectItem, ideaItem, nowTime)
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.RemoveIdeaNotice{
		ProjectId: req.ProjectId,
		IdeaId:    req.IdeaId,
	})
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_idea.UpdateGroupNotice{
		ProjectId:   req.ProjectId,
		IdeaGroupId: ideaItem.IdeaGroupId,
	})
	return ret.(*project_idea_api.RemoveIdeaResponse), nil
}

func (apiImpl *ProjectIdeaApiImpl) ListAllKeyword(ctx context.Context, req *project_idea_api.ListAllKeywordRequest) (*project_idea_api.ListAllKeywordResponse, error) {
	emptyList := []string{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_idea_api.ListAllKeywordResponse{
			Code:        project_idea_api.ListAllKeywordResponse_CODE_WRONG_SESSION,
			ErrMsg:      "会话不存在",
			KeywordList: emptyList,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_idea_api.ListAllKeywordResponse{
			Code:        project_idea_api.ListAllKeywordResponse_CODE_NO_PROJECT,
			ErrMsg:      "项目不存在",
			KeywordList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_idea_api.ListAllKeywordResponse{
			Code:        project_idea_api.ListAllKeywordResponse_CODE_NO_PERMISSION,
			ErrMsg:      "没有权限",
			KeywordList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}
	keywordList, err := idea_dao.IdeaDao.ListAllKeyword(ctx, req.ProjectId)
	if err != nil {
		return nil, err
	}
	return &project_idea_api.ListAllKeywordResponse{
		Code:        project_idea_api.ListAllKeywordResponse_CODE_OK,
		KeywordList: keywordList,
	}, nil
}
